﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Damany.Imaging.Common;
using Damany.PortraitCapturer.DAL;
using Damany.RemoteImaging.Common;
using Damany.Util;
using RemoteControlService;
using RemoteImaging.LicensePlate;
using Video = RemoteImaging.Core.Video;
using Damany.Util.Extensions;

namespace RemoteImaging.Query
{
    using LicensePlate;

    public class VideoQueryPresenter : IVideoQueryPresenter
    {
        private readonly IVideoQueryScreen _screen;
        private DevExpress.Xpo.Session _session;
        private readonly ConfigurationManager _manager;
        private Damany.PC.Domain.CameraInfo _selectedCamera;
        private DateTimeRange _range;
        private SearchScope _scope;
        private DateTimeRange _currentRange;
        private readonly IVisualStateManager _visualStateManager;
        private readonly IMessageBoxService _messageBoxService;

        public VideoQueryPresenter(IVideoQueryScreen screen,
                                   ConfigurationManager manager,
                                   IVisualStateManager visualStateManager,
                                   IMessageBoxService messageBoxService)
        {
            _messageBoxService = messageBoxService;
            _visualStateManager = visualStateManager;
            _screen = screen;
            _manager = manager;
        }

        public void Start()
        {
            _screen.AttachPresenter(this);
            _screen.Cameras = _manager.GetCameras().ToArray();
            _screen.Show();

        }


        public async void Search(DevExpress.Xpo.Session session)
        {
            try
            {
                _visualStateManager.IsBusy = true;

                var selectedCamera = this._screen.SelectedCamera;
                if (selectedCamera == null)
                {
                    return;
                }


                _selectedCamera = this._screen.SelectedCamera;
                _range = this._screen.TimeRange;
                _scope = this._screen.SearchScope;

                _currentRange = new DateTimeRange(_range.From, _range.From.AddHours(1));


                var t = await FindFirstVideo();

                if (t.Count <= 0)
                {
                    return;
                }

                _range.From = t.First().CapturedAt;
                _range.To = t.Last().CapturedAt;

                UpdateCurrentRange(t);

                _visualStateManager.IsBusy = true;

                SearchAsync(session);
            }
            catch (Exception ex)
            {
                _messageBoxService.ShowError(ex.Message);
            }
            finally
            {
                _visualStateManager.IsBusy = false;

            }

        }

        private void SearchAsync(DevExpress.Xpo.Session session)
        {
            _session = session;

            ThreadPool.QueueUserWorkItem(o => DoSearch());
        }
        public void PlayVideo()
        {
            var p = this._screen.SelectedVideoFile;
            if (p == null) return;
            if (string.IsNullOrEmpty(p.Path))
                return;
            if (!System.IO.File.Exists(p.Path))
                return;

            this._screen.PlayVideoInPlace(p.Path);
        }

        public void ShowRelatedFaces()
        {
            var range = GetSelectedVideoTimeRange();
        }

        public void ShowRelatedLicenseplates()
        {

        }

        private DateTimeRange GetSelectedVideoTimeRange()
        {
            var video = _screen.SelectedVideoFile;

            var from = video.CapturedAt.RoundToMinute();
            var to = from.AddMinutes(1);

            return new DateTimeRange(from, to);
        }

        public void NextPage()
        {
            if (_selectedCamera == null)
                return;

            if (_currentRange.To.AddHours(1) > _range.To)
            {
                return;
            }

            _currentRange.From = _currentRange.From.AddHours(1);
            _currentRange.To = _currentRange.To.AddHours(1);

            UpdateScreenTimeRange();
            SearchAsync(_session);
        }

        public void PreviousPage()
        {
            if (_selectedCamera == null)
                return;

            if (_currentRange.From.AddHours(-1) < _range.From)
            {
                return;
            }

            _currentRange.From = _currentRange.From.AddHours(-1);
            _currentRange.To = _currentRange.To.AddHours(-1);

            UpdateScreenTimeRange();
            SearchAsync(_session);
        }

        public void FirstPage()
        {
            if (_selectedCamera == null)
                return;

            _currentRange.From = _range.From;
            _currentRange.To = _currentRange.From.AddHours(1);

            UpdateScreenTimeRange();

            SearchAsync(_session);
        }

        public void LastPage()
        {
            if (_selectedCamera == null)
                return;


            _currentRange.To = _range.To;
            _currentRange.From = _range.To.AddHours(-1);

            UpdateScreenTimeRange();
            SearchAsync(_session);
        }

        private void DoSearch()
        {

            try
            {
                _visualStateManager.IsBusy = true;
                var videos =
                new FileSystemStorage().
                    VideoFilesBetween(_selectedCamera.Id,
                                      _currentRange.From, _currentRange.To).ToList();

                var watch = System.Diagnostics.Stopwatch.StartNew();
                var range = new DateTimeRange(_currentRange.From, _currentRange.To.AddMinutes(1));

                watch.Stop();
                System.Diagnostics.Debug.WriteLine("frames search took " + watch.Elapsed);

                watch.Start();

                watch.Stop();
                System.Diagnostics.Debug.WriteLine("portraits search took " + watch.Elapsed);

                var cretia = GetLicensePlateQueryCretia(range);

                var lpiQuery = Helper.FindLicensePlateBy(range.From, range.To, _session);
                var lpiHash = new HashSet<DateTime>();
                foreach (var licensePlateInfo in lpiQuery)
                {
                    var roundup = licensePlateInfo.CaptureTime.RoundToMinute();
                    lpiHash.Add(roundup);
                }

                this._screen.ClearAll();

                foreach (var v in videos)
                {
                    if (v.CapturedAt.Ticks < _currentRange.From.Ticks || v.CapturedAt.Ticks > _currentRange.To.Ticks)
                    {
                        continue;
                    }

                    //v.HasFaceCaptured =
                    //    portraitHash.Contains(v.CapturedAt);
                    //v.HasLicenseplateCaptured = lpiHash.Contains(v.CapturedAt);

                    //if ((_scope & SearchScope.FaceCapturedVideo)
                    //    == SearchScope.FaceCapturedVideo)
                    //{
                    //    if (v.HasFaceCaptured)
                    //    {
                    //        _screen.AddVideo(v);
                    //    }
                    //}

                    if ((_scope & SearchScope.MotionWithoutFaceVideo)
                        == SearchScope.MotionWithoutFaceVideo)
                    {
                        if (v.HasMotionDetected && !v.HasFaceCaptured)
                        {
                            _screen.AddVideo(v);
                        }
                    }

                    if ((_scope & SearchScope.MotionLessVideo)
                        == SearchScope.MotionLessVideo)
                    {
                        if (!v.HasFaceCaptured &&
                            !v.HasMotionDetected)
                        {
                            _screen.AddVideo(v);
                        }
                    }

                }

            }
            finally
            {
                _visualStateManager.IsBusy = false;
            }


        }

        private SearchCretia GetLicensePlateQueryCretia(DateTimeRange range)
        {
            var cretia = new SearchCretia();
            cretia.AddCretia(lpi => lpi.CaptureTime >= range.From && lpi.CaptureTime <= range.To);
            return cretia;
        }

        private void UpdateScreenTimeRange()
        {
            _screen.CurrentRange = _currentRange;
        }

        private async Task<List<Video>> FindFirstVideo()
        {
            var videos = await TaskEx.Run(() =>
                new FileSystemStorage().
                    VideoFilesBetween(_selectedCamera.Id,
                                      _range.From, _range.To).ToList());


            return videos;
        }

        private void UpdateCurrentRange(List<Video> videos)
        {
            _currentRange.From = videos.First().CapturedAt;
            _currentRange.To = _currentRange.From.AddHours(1);

            UpdateScreenTimeRange();
        }
    }
}
